package edu.ccut.saturn.studio.database.ui;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.part.ViewPart;

import edu.ccut.saturn.studio.core.util.eclipse.Messages;
import edu.ccut.saturn.studio.core.util.eclipse.SaturnDialogUtil;
import edu.ccut.saturn.studio.database.model.DBConnection;
import edu.ccut.saturn.studio.database.model.DBConnectionProvider;
import edu.ccut.saturn.studio.database.model.SaturnTree;
import edu.ccut.saturn.studio.database.model.DBConnection.DBConnectionListener;
import edu.ccut.saturn.studio.database.popup.action.MngDBConnectionAction;
import edu.ccut.saturn.studio.database.popup.action.NewDBConnectionAction;

/**
 * 数据库连接视图
 * 
 * @author 谷钰
 * 
 * @version 1.0
 */
public class DBConnectView extends ViewPart {

	private static DBConnectView instance;
	
	public TreeViewer viewer;

	private List<SaturnTree> selecteds = new ArrayList<SaturnTree>();

	private MngDBConnectionAction mngConnectionAction;

	private NewDBConnectionAction newDBconAction;

	private SaturnTree invisibleRoot;

	class ViewContentProvider implements IStructuredContentProvider,
			ITreeContentProvider {

		public void inputChanged(Viewer viewer1, Object obj, Object obj1) {
		}

		public void dispose() {
		}

		public Object[] getElements(Object obj) {
			if (obj.equals(getViewSite())) {
				if (invisibleRoot == null) {
					initialize();
				}
				return getChildren(invisibleRoot);
			}

			return getChildren(obj);
		}

		public Object getParent(Object obj) {
			if (obj instanceof SaturnTree) {
				return ((SaturnTree) obj).getParent();
			}

			return null;
		}

		public Object[] getChildren(Object obj) {
			if (obj instanceof SaturnTree) {
				SaturnTree saturnTree = (SaturnTree) obj;
				List<SaturnTree> children = saturnTree.getChildren();
				return children.toArray(new SaturnTree[children.size()]);
			}

			return new Object[0];
		}

		public boolean hasChildren(Object obj) {
			if (obj instanceof SaturnTree) {
				return ((SaturnTree) obj).hasChildren();
			}

			return false;
		}

		public void initialize() {
			invisibleRoot = new SaturnTree(""); //$NON-NLS-1$
			invisibleRoot.addChildren(DBConnectionProvider.getInstance()
					.getAllDBConnections());
		}
	}

	class ViewLabelProvider extends LabelProvider {
		public String getText(Object obj) {
			return obj.toString();
		}

		public Image getImage(Object obj) {
			Image image = super.getImage(obj);

			if (obj instanceof SaturnTree) {
				SaturnTree saturnTree = (SaturnTree) obj;

				image = saturnTree.getImage();
			}

			return image;
		}
	}

	public DBConnectView() {
		instance = this;
	}

	public static DBConnectView getInstance() {
		return instance; //$NON-NLS-1$
	}

	public void addDbConnection(DBConnection dbConnection) {
		this.invisibleRoot.addChild(dbConnection);
		this.refresh();
	}

	public void removeDbConnection(DBConnection dbConnection) throws Exception {
		this.invisibleRoot.removeChild(dbConnection);
		this.refresh();

		dbConnection.setOpen(false); //$NON-NLS-1$
		dbConnection.removeChildren();
		dbConnection.closeConnection();
	}

	public void createPartControl(Composite composite) {
		viewer = new TreeViewer(composite, 770);
		viewer.setContentProvider(new ViewContentProvider());
		viewer.setLabelProvider(new ViewLabelProvider());
		viewer.addOpenListener(new IOpenListener() {

			public void open(OpenEvent openevent) {
				Object obj = ((StructuredSelection) openevent.getSelection())
						.getFirstElement();
				if (obj instanceof DBConnection) {
					final DBConnection dbConnection = (DBConnection) obj;

					dbConnection.getConnectionAsync(new DBConnectionListener() {
						public void onGetConnection(Connection connection) {
							getSite().getShell().getDisplay().asyncExec(
								new Runnable() {
									public void run() {
										try {
											expand(dbConnection);
										} catch (Exception e) {
											SaturnDialogUtil.openError(
													getSite().getShell(), e
															.getMessage());
										}
									}
								});
						}
					});
				} else if (obj instanceof SaturnTree) {
					SaturnTree saturnTree = (SaturnTree) obj;

					try {
						expand(saturnTree);
					} catch (Exception e) {
						SaturnDialogUtil.openError(getSite().getShell(), e
								.getMessage());
					}
				}
			}

		});

		viewer.addSelectionChangedListener(new ISelectionChangedListener() {

			@SuppressWarnings("unchecked") //$NON-NLS-1$
			public void selectionChanged(
					SelectionChangedEvent selectionchangedevent) {

				selecteds.clear();

				Iterator selected = ((IStructuredSelection) viewer
						.getSelection()).iterator();

				while (selected.hasNext()) {
					Object select = selected.next();

					if (select instanceof SaturnTree) {
						selecteds.add((SaturnTree) select);
					}
				}
			}
		});

		viewer.setSorter(new ViewerSorter());
		viewer.setInput(getViewSite());
		makeActions();
		contributeToActionBars();
		hookContextMenu();
	}

	private void hookContextMenu() {
		MenuManager menumanager = new MenuManager("#PopupMenu"); //$NON-NLS-1$
		menumanager.setRemoveAllWhenShown(true);
		menumanager.addMenuListener(new IMenuListener() {

			public void menuAboutToShow(IMenuManager imenumanager) {
				fillContextMenu(imenumanager);
				if (!invisibleRoot.hasChildren()) {
					imenumanager.add(newDBconAction);
				}
			}

		});
		Menu menu = menumanager.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		getSite().registerContextMenu(menumanager, viewer);
	}

	private void fillContextMenu(IMenuManager imenumanager) {
		imenumanager.add(new Separator("additions")); //$NON-NLS-1$
	}

	private void contributeToActionBars() {
		IActionBars iactionbars = getViewSite().getActionBars();
		fillLocalToolBar(iactionbars.getToolBarManager());
	}

	private void fillLocalToolBar(IToolBarManager itoolbarmanager) {
		itoolbarmanager.add(mngConnectionAction);
	}

	private void makeActions() {
		mngConnectionAction = new MngDBConnectionAction();
		mngConnectionAction.setText(Messages.getString("DBConnectView.create")); //$NON-NLS-1$
		newDBconAction = new NewDBConnectionAction();
		newDBconAction.setText(Messages.getString("DBConnectView.create")); //$NON-NLS-1$
	}

	public void setFocus() {
		viewer.getControl().setFocus();
	}

	public List<SaturnTree> getCurrentSelections() {
		return this.selecteds;
	}

	public void expand(SaturnTree tree) throws Exception {
		tree.expand();
		getViewer().refresh();
		setSelected(tree);
		update(tree);
	}

	public void update(SaturnTree treeobjectparent) {
		viewer.expandToLevel(treeobjectparent, 1);
	}

	public void refresh() {
		((ViewContentProvider) viewer.getContentProvider()).initialize();
		viewer.refresh();
	}

	public TreeViewer getViewer() {
		return viewer;
	}

	public void setSelected(final Object node) {
		getSite().getShell().getDisplay().asyncExec(new Runnable() {
			public void run() {
				StructuredSelection structuredselection = new StructuredSelection(
						node);
				viewer.setSelection(structuredselection, true);
			}
		});
	}

}
